package jdos.gui;

import jdos.hardware.Hardware;
import jdos.misc.Log;
import jdos.util.Ptr;

public class Render {
    // 0: complex scalers off, scaler cache off, some simple scalers off, memory requirements reduced
    // 1: complex scalers off, scaler cache off, all simple scalers on
    // 2: complex scalers off, scaler cache on
    // 3: complex scalers on
    static public final int RENDER_USE_ADVANCED_SCALERS = 0;

    static public final int RENDER_SKIP_CACHE = 16;
    //Enable this for scalers to support 0 input for empty lines
    //#define RENDER_NULL_INPUT


    public static class Render_t {
        public static class SRC {
            public /*Bitu*/int width, start;
            public /*Bitu*/int height;
            public /*Bitu*/int bpp;
            public boolean dblw,dblh;
            public double ratio;
            public float fps;
            public /*Bitu*/int outPitch;
            public /*Bit8u*/int[] outWrite32;
            public int outWriteOff;
        }
        public SRC src = new SRC();
        public static class Frameskip {
            public /*Bitu*/int count;
            public /*Bitu*/int max;
            public /*Bitu*/int index;
            public boolean auto;
            public /*Bit8u*/boolean[] hadSkip = new boolean[RENDER_SKIP_CACHE];
        }
        public Frameskip frameskip = new Frameskip();
        public boolean updating;
        public boolean active;
        public boolean aspect;
        public boolean fullFrame;
        public int scale = 2;
        public boolean scaleForced = false;
    }

    static public Render_t render;

    public static boolean RENDER_StartUpdate() {
        if (render.updating)
            return false;
        if (!render.active)
            return false;
        if (render.frameskip.count<render.frameskip.max) {
            render.frameskip.count++;
            return false;
        }
        render.frameskip.count=0;

        Main.GFX_StartUpdate(render.src);
        render.src.outWriteOff = 0;

        /* Clearing the cache will first process the line to make sure it's never the same */
        render.fullFrame = true;
        render.updating = true;
        return true;
    }

    static private void RENDER_Halt() {
        Main.GFX_EndUpdate();
        render.updating=false;
        render.active=false;
    }

    static public void RENDER_EndUpdate( boolean abort ) {
        if (!render.updating)
            return;
        if ((Hardware.CaptureState & (Hardware.CAPTURE_IMAGE|Hardware.CAPTURE_VIDEO))!=0) {
            /*Bitu*/int pitch, flags;
            flags = 0;
            if (render.src.dblw != render.src.dblh) {
                if (render.src.dblw) flags|=Hardware.CAPTURE_FLAG_DBLW;
                if (render.src.dblh) flags|=Hardware.CAPTURE_FLAG_DBLH;
            }
            float fps = render.src.fps;
            pitch = render.src.outPitch;
            if (render.frameskip.max!=0)
                fps /= 1+render.frameskip.max;
            //Hardware.CAPTURE_AddImage( render.src.width, render.src.height, render.src.bpp, pitch, flags, fps, render.src.outWrite, render.pal.rgb );
        }
            Main.GFX_EndUpdate();
            render.frameskip.hadSkip[render.frameskip.index] = false;

        render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1);
        render.updating=false;
    }

    private static void RENDER_Reset() {
        /*Bitu*/int width=render.src.width;
        /*Bitu*/int height=render.src.height;

        if (render.src.dblh && render.src.dblw || (render.scaleForced && !render.src.dblh && !render.src.dblw)) {
            width*=render.scale;
            height*=render.scale;
        } else if (render.src.dblw) {
            width*=2;
        } else if (render.src.dblh) {
            height*=2;
        }
        //Main.GFX_SetSize(width,height, render.src.width, render.src.height, Render.render.aspect,Render.render.src.bpp);

        //Finish this frame using a copy only handler
        render.src.outWrite32 = null;
        /* Signal the next frame to first reinit the cache */
        render.active=true;
    }

    static private Main.GFX_CallBack_t RENDER_CallBack = new Main.GFX_CallBack_t() {
        public void call(int function) {
            if (function == Main.GFX_CallBackFunctions_t.GFX_CallBackStop) {
                RENDER_Halt( );
            } else if (function == Main.GFX_CallBackFunctions_t.GFX_CallBackRedraw) {
            } else if ( function == Main.GFX_CallBackFunctions_t.GFX_CallBackReset) {
                Main.GFX_EndUpdate();
                RENDER_Reset();
            } else {
                Log.exit("Unhandled GFX_CallBackReset "+function );
            }
        }
    };

    public static void RENDER_SetSize(/*Bitu*/int width,/*Bitu*/int height,/*Bitu*/int bpp,float fps,double ratio,boolean dblw,boolean dblh) {
        RENDER_Halt( );
        if (width==0 || height==0 ) {
            return;
        }
        if ( ratio > 1 ) {
            double target = height * ratio + 0.1;
            ratio = target / height;
        } else {
            //This would alter the width of the screen, we don't care about rounding errors here
        }
        render.src.width=width;
        render.src.height=height;
        render.src.bpp=bpp;
        render.src.dblw=dblw;
        render.src.dblh=dblh;
        render.src.fps=fps;
        render.src.ratio=ratio;
        RENDER_Reset( );
    }

    private static Mapper.MAPPER_Handler IncreaseFrameSkip = new Mapper.MAPPER_Handler() {
        public void call(boolean pressed) {
            if (!pressed)
                return;
            if (render.frameskip.max<10) render.frameskip.max++;
            Log.log_msg("Frame Skip at "+render.frameskip.max);
            Main.GFX_SetTitle(-1,render.frameskip.max,false);
        }
    };

    private static Mapper.MAPPER_Handler DecreaseFrameSkip = new Mapper.MAPPER_Handler() {
        public void call(boolean pressed) {
            if (!pressed)
                return;
            if (render.frameskip.max>0) render.frameskip.max--;
            Log.log_msg("Frame Skip at "+render.frameskip.max);
            Main.GFX_SetTitle(-1,render.frameskip.max,false);
        }
    };

    static boolean running = false;
    public static void RENDER_Init() {
        render = new Render_t();
        render.aspect=MainFrameCCPAL.aspect;//false
        render.frameskip.max=MainFrameCCPAL.frameskip;//0
        if (render.frameskip.max<0) {
            render.frameskip.max = 0;
            render.frameskip.auto = true;
        }
        render.scale = MainFrameCCPAL.scaler;//1,2,3

        render.scaleForced = MainFrameCCPAL.scaleForced;

        render.frameskip.count=0;

        if(!running) render.updating=true;
        running = true;

        Main.GFX_SetTitle(-1,render.frameskip.max,false);
    }
}
